﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using FlatRedBall;
using Rvz.Game.Main.Common;
using Rvz.Game.Main.Entities.Projectiles;
using Rvz.Game.Main.Entities.Projectiles.States;
using Rvz.Game.Main.Entities.Robots;
using Rvz.Game.Main.State;

namespace Rvz.Game.Main.Rules
{
    public static class ProjectileEngine
    {
        private static readonly ICollection<Projectile> Projectiles = new Collection<Projectile>();
        public static IEnumerable<Projectile> ActiveProjectiles
        {
            get { return Projectiles.ToArray(); }
        }

        public static void AddProjectile(Projectile projectile)
        {
            Projectiles.Add(projectile);
        }

        public static void RemoveProjectile(Projectile projectile)
        {
            Projectiles.Remove(projectile);
        }

        public static void Fire(Robot robot, GameState gameState)
        {
            var robotAttributes = robot.RobotAttributes;
            var fixedRotation = robot.RotationZ + (Math.PI / 2);
            //TODO: Make the weapon create the projectile
            var projectile = new Projectile(gameState.ContentManagerName, robotAttributes.CurrentWeapon.TravelSpeed) { Position = robot.Position };
            projectile.XVelocity = (float)(projectile.TravelSpeed * Math.Cos(fixedRotation));
            projectile.YVelocity = (float)(projectile.TravelSpeed * Math.Sin(fixedRotation));
            AddProjectile(projectile);
        }

        public static void ProcessRules(GameState gameState)
        {
            ExpireProjectiles();
            ActivateProjectiles(gameState);
        }

        private static void ActivateProjectiles(GameState gameState)
        {
            ActiveProjectiles.ForEach(x => BuildStates(x, gameState));
            ActiveProjectiles.ForEach(x => x.ProcessStates(gameState));
        }

        private static void BuildStates(Projectile projectile, GameState gameState)
        {
            //TODO: Cleanup/refactor into somethin besides two nested foreach loops. Maybe a method that checks collisions between two collections
            var waveState = gameState.WaveState;
            var zombies = waveState.ActiveZombies;
            zombies.ForEach(z =>
                                {
                                    if (projectile.CollisionShape.CollideAgainst(z.CollisionShape))
                                    { projectile.AddState(new ZombieCollisionState(z)); }
                                });
        }

        private static void ExpireProjectiles()
        {
            foreach (var projectile in ActiveProjectiles)
            {
                //TODO: Expire projectiles after a few seconds as well
                if (SpriteManager.Camera.IsPointInView(projectile.Position.X, projectile.Position.Y, projectile.Position.Z))
                { continue; }

                projectile.Destroy();
                RemoveProjectile(projectile);
            }
        }

        public static void Reset()
        {
            ActiveProjectiles.ForEach(p =>
                                              {
                                                  p.Destroy();
                                                  Projectiles.Remove(p);
                                              });
        }
    }
}
